package com.Cychat.auth.service.Impl;

import cn.hutool.jwt.Claims;
import com.Cychat.auth.entity.DO.WxParamsDO;
import com.Cychat.auth.entity.VO.LoginParamsVO;
import com.Cychat.auth.mapper.UserMapper;
import com.Cychat.auth.params.LoginParams;
import com.Cychat.auth.service.LoginService;
import com.Cychat.auth.service.UserService;
import com.Cychat.auth.utils.GetWxOpenid;
import com.Cychat.commons.entity.ResultMessage;
import com.Cychat.commons.entity.pojo.User;
import com.Cychat.commons.utils.JWTUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.Date;


/**
 * Auther: 刘博文
 * Date: 2025/10/29:14:14
 * Description: 登录服务实现类
 * 
 * Token验证策略说明：
 * 1. Access Token: 主要使用JWT签名验证（性能优先），黑名单作为补充（安全）
 * 2. Refresh Token: 必须同时验证JWT签名和Redis存储（确保是服务端签发的）
 * 3. 混合验证：先JWT验证（快速），再黑名单检查（安全），最后Redis验证（refresh token）
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class LoginServiceImpl extends ServiceImpl<UserMapper, User> implements LoginService{
    // redis工具对象
    private final RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private GetWxOpenid getWxOpenid;

    @Autowired
    private UserService userService;
    @Override
    public ResultMessage<LoginParamsVO> login(LoginParams code, HttpServletResponse response) {
        try {
            // 调用微信接口获取openid和session_key
            WxParamsDO openidFromWechat = getWxOpenid.getOpenidFromWechat(code.getCode());
            String openid = openidFromWechat.getOpenid();
            // 查找用户是否已经存在
            User user = userService.findByOpenid(openid);

            // 如果用户不存在，则创建新用户
            if (user == null) {
                user = new User();
                user.setNickName(code.getNickName());
                user.setAvatarUrl(code.getAvatarUrl());
                user.setOpenid(openid);
                user.setLanguage("简体中文");
                user.setGender(0);
                // 设置其他默认值
                userService.createUser(user);
            }
            // 返回登录成功信息
            LoginParamsVO loginParamsVO = new LoginParamsVO();
            BeanUtils.copyProperties(user, loginParamsVO);
            loginParamsVO.setUserId(String.valueOf(user.getUserId()));
            // 生成token、retoken
            String token = JWTUtil.generateToken(user.getUserId());
            String retoken = JWTUtil.generateRefreshToken(user.getUserId());

            // 为每个用户维护唯一的refresh token，避免重复存储
            String userRefreshTokenKey = "user_refresh_token:" + user.getUserId();

            // 如果用户已有旧的token，先清理
            String oldRetoken = (String) redisTemplate.opsForValue().get(userRefreshTokenKey);
            if (oldRetoken != null) {
                String oldRetokenTid = JWTUtil.getJti(oldRetoken);
                if (oldRetokenTid != null) {
                    // 删除旧的refresh token
                    redisTemplate.delete("refresh_token_id:" + oldRetokenTid);
                }
            }

            // 清理用户可能存在的旧access token（通过userId查找）
            // 注意：这里需要根据你的实际存储方式调整
            // 如果token存储时没有userId索引，可能需要其他方式清理
            
            // 将token和retoken存储到redis中方便后续验证
            String tokenTid = JWTUtil.getJti(token);
            String retokenTid = JWTUtil.getJti(retoken);

            redisTemplate.opsForValue().set("token_id:" + tokenTid,
                    "validToken", Duration.ofMillis(JWTUtil.TOKEN_EXPIRE_TIME));
            redisTemplate.opsForValue().set("refresh_token_id:" + retokenTid,
                    "rightLogin", Duration.ofMillis(JWTUtil.REFRESH_TOKEN_EXPIRE_TIME));

            // 存储用户与refresh token的映射关系
            redisTemplate.opsForValue().set(userRefreshTokenKey, retoken,
                    Duration.ofMillis(JWTUtil.REFRESH_TOKEN_EXPIRE_TIME));

            // 将token、refresh放到响应头里面（保持格式一致，不使用Bearer前缀，与前端约定一致）
            response.setHeader("authorization", token);
            response.setHeader("retoken", retoken);

            // 局部设置
            response.setHeader("Access-Control-Expose-Headers", "authorization, retoken");

            return ResultMessage.success(loginParamsVO);
        } catch (Exception e) {
            return ResultMessage.error("微信登录失败: " + e.getMessage());
        }
    }

    @Override
    public ResultMessage<String> logout(HttpServletRequest request) {
        try {
            String token = null;
            String retoken = null;
            
            // 获取token
            String authHeader = request.getHeader("authorization");
            if (authHeader != null && authHeader.startsWith("Bearer ")) {
                token = authHeader.substring(7);
            } else if (authHeader != null) {
                token = authHeader;
            }

            // 获取retoken
            String retokenHeader = request.getHeader("retoken");
            if (retokenHeader != null && retokenHeader.startsWith("Bearer ")) {
                retoken = retokenHeader.substring(7);
            } else if (retokenHeader != null) {
                retoken = retokenHeader;
            }

            if (token == null || token.isEmpty()) {
                return ResultMessage.error("未提供有效的token");
            }

            // 解析JWT 获取到 exp
            Date exp = JWTUtil.getExpiration(token);
            if (exp == null) {
                return ResultMessage.error("无效的token");
            }

            // 计算过期时间
            long expireTime = exp.getTime() - System.currentTimeMillis();
            // 未过期解析token的tid
            if (expireTime > 0) {
                String tid = JWTUtil.getJti(token);
                if (tid != null && !tid.isEmpty()) {
                    // 保存token的tid到redis的黑名单
                    redisTemplate.opsForValue().set("lastlist:jwt:" + tid,
                            "logout",
                            Duration.ofMillis(expireTime));
                    
                    // 同时删除redis中的token记录
                    redisTemplate.delete("token_id:" + tid);
                } else {
                    return ResultMessage.error("无法获取token的ID");
                }
            }

            // 处理refresh token
            if (retoken != null && !retoken.isEmpty()) {
                Date retokenExp = JWTUtil.getExpiration(retoken);
                if (retokenExp != null) {
                    long retokenExpireTime = retokenExp.getTime() - System.currentTimeMillis();
                    if (retokenExpireTime > 0) {
                        String retokenTid = JWTUtil.getJti(retoken);
                        if (retokenTid != null && !retokenTid.isEmpty()) {
                            // 删除refresh token记录
                            redisTemplate.delete("refresh_token_id:" + retokenTid);
                            
                            // 删除用户与refresh token的映射
                            Long userId = JWTUtil.getuid(retoken);
                            if (userId != null && userId > 0) {
                                redisTemplate.delete("user_refresh_token:" + userId);
                            }
                        }
                    }
                }
            }

            return ResultMessage.success("登出成功");
        } catch (Exception e) {
            log.error("登出失败", e);
            return ResultMessage.error("登出失败: " + e.getMessage());
        }
    }
    /**
     * Description : 查看refresh token是否过期
     * ChangeLog : 1. 创建 (2025/11/5 16:41 [Esang]);
     * @param retoken
     * @return null
     */
    public Long getRefreshTokenExpired(String retoken) {
        String retokenTid = JWTUtil.getJti(retoken);
        return redisTemplate.getExpire("refresh_token_id:"+retokenTid);
    }
}